package com.ias.redis.config;

import com.ias.redis.serializer.SerializerFactory;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.autoconfigure.AutoConfiguration;
import org.springframework.boot.autoconfigure.condition.ConditionalOnMissingBean;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.boot.context.properties.EnableConfigurationProperties;
import org.springframework.cache.CacheManager;
import org.springframework.cache.annotation.EnableCaching;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
import org.springframework.data.redis.cache.RedisCacheConfiguration;
import org.springframework.data.redis.cache.RedisCacheManager;
import org.springframework.data.redis.cache.RedisCacheWriter;
import org.springframework.data.redis.connection.RedisConnectionFactory;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.data.redis.serializer.RedisSerializationContext;
import org.springframework.data.redis.serializer.RedisSerializer;


/**
 * Redis自动配置类
 *
 * @author IAS Team
 * @version 2.0.0
 */
@Slf4j
@AutoConfiguration
@EnableConfigurationProperties(RedisProperties.class)
@ConditionalOnProperty(prefix = "ias.redis", name = "enabled", havingValue = "true", matchIfMissing = true)
@RequiredArgsConstructor
@EnableCaching
public class RedisAutoConfiguration {

    private final RedisProperties redisProperties;

    public void logConfig() {
        log.info("IAS Redis Auto Configuration initialized with properties: {}", redisProperties);
    }

    /**
     * Redis模板配置
     */
    @Bean
    @Primary
    @ConditionalOnMissingBean(name = "redisTemplate")
    public RedisTemplate<Object, Object> redisTemplate(RedisConnectionFactory connectionFactory) {
        RedisTemplate<Object, Object> template = new RedisTemplate<>();
        template.setConnectionFactory(connectionFactory);

        // 配置序列化器
        RedisSerializer<String> keySerializer = SerializerFactory.createKeySerializer();
        RedisSerializer<Object> valueSerializer = createValueSerializer();

        template.setKeySerializer(keySerializer);
        template.setHashKeySerializer(keySerializer);
        template.setValueSerializer(valueSerializer);
        template.setHashValueSerializer(valueSerializer);

        template.setDefaultSerializer(valueSerializer);
        template.afterPropertiesSet();

        log.info("Redis template configured with serialization type: {}", 
                redisProperties.getSerialization().getType());
        return template;
    }

    /**
     * String Redis模板
     */
    @Bean
    @ConditionalOnMissingBean
    public StringRedisTemplate stringRedisTemplate(RedisConnectionFactory connectionFactory) {
        StringRedisTemplate template = new StringRedisTemplate();
        template.setConnectionFactory(connectionFactory);
        return template;
    }

    /**
     * 缓存管理器配置 提供兜底保障（防御性编程）
     */
    @Bean
    @ConditionalOnMissingBean
    public CacheManager cacheManager(RedisConnectionFactory connectionFactory) {
        RedisProperties.Cache cacheConfig = redisProperties.getCache();
        
        RedisCacheConfiguration config = RedisCacheConfiguration.defaultCacheConfig()
                .entryTtl(cacheConfig.getDefaultTtl())
                .serializeKeysWith(RedisSerializationContext.SerializationPair.fromSerializer(
                        SerializerFactory.createKeySerializer()))
                .serializeValuesWith(RedisSerializationContext.SerializationPair.fromSerializer(
                        createValueSerializer()));

        if (!cacheConfig.isAllowNullValues()) {
            config = config.disableCachingNullValues();
        }

        if (cacheConfig.isUseKeyPrefix()) {
            config = config.prefixCacheNameWith(cacheConfig.getKeyPrefix());
        }

        return RedisCacheManager.builder(RedisCacheWriter.nonLockingRedisCacheWriter(connectionFactory))
                .cacheDefaults(config)
                .build();
    }


    /**
     * 创建值序列化器
     */
    private RedisSerializer<Object> createValueSerializer() {
        RedisProperties.Serialization serializationConfig = redisProperties.getSerialization();
        RedisSerializer<Object> serializer = SerializerFactory.createValueSerializer(serializationConfig.getType());
        
        if (serializationConfig.isCompress()) {
            serializer = SerializerFactory.createCompressedSerializer(
                    serializer, 
                    serializationConfig.getCompressThreshold()
            );
            log.info("Compression enabled with threshold: {} bytes", 
                    serializationConfig.getCompressThreshold());
        }
        
        return serializer;
    }
} 